package system

import (
	"gorm.io/gorm"
	"server/global"
	comRequest "server/model/common/request"
	sysModel "server/model/system"
	sysRequest "server/model/system/request"
)

type RoleService struct {
}

var RoleServiceApp = new(RoleService)

//获取分页数据
func (r *RoleService) GetList(p *sysRequest.SysRoleGetList) ([]*sysModel.SysRole, int64, error) {
	var total int64
	list := ([]*sysModel.SysRole)(nil)
	tx := global.GvaDb.Model(&sysModel.SysRole{})
	if p.Name != "" {
		tx = tx.Where("name like ?", "%"+p.Name+"%")
	}
	if p.DisplayName != "" {
		tx = tx.Where("display_name like ?", "%"+p.DisplayName+"%")
	}
	rs := tx.Count(&total).Order("order_num ASC, id ASC").Limit(int(p.PageSize)).Offset(int((p.PageNo - 1) * p.PageSize)).Find(&list)
	return list, total, rs.Error
}

//获取指定用户的角色ID数组集
func (r *RoleService) GetUserRoleIds(userId uint) []uint {
	var list []sysModel.SysUserRole
	var userRoleIds []uint
	//用户-角色中间表记录数据
	global.GvaDb.Where(&sysModel.SysUserRole{SysUserId: userId}).Find(&list)
	for _, v := range list {
		userRoleIds = append(userRoleIds, v.SysRoleId)
	}
	return userRoleIds
}

//通过用户ID获取角色列表
func (r *RoleService) GetRoleListByUserId(userId uint) ([]*sysModel.SysRole, error) {
	//用户-角色中间表记录数据
	userRoleIds := r.GetUserRoleIds(userId)
	roleList := ([]*sysModel.SysRole)(nil)
	//角色列表
	result := global.GvaDb.Where("id in ?", userRoleIds).Find(&roleList)
	return roleList, result.Error
}

// 获取角色名称列表
func (r *RoleService) GetRoleNameListByUserId(userId uint) []string {
	var list []*sysModel.SysRole
	var roleNameList []string
	//用户-角色中间表记录数据
	userRoleIds := r.GetUserRoleIds(userId)
	global.GvaDb.Where(userRoleIds).Find(&list)
	for _, v := range list {
		roleNameList = append(roleNameList, v.Name)
	}
	return roleNameList
}

//保存角色数据
func (r *RoleService) SaveRole(data *sysModel.SysRole) error {
	var err error
	//使用事务闭包
	return global.GvaDb.Transaction(func(tx *gorm.DB) error {
		if data.ID != 0 {
			if err = tx.Model(&sysModel.SysRole{}).Where("id = ?", data.ID).Updates(&data).Error; err != nil {
				return err
			}
		} else {
			if err = tx.Create(&data).Error; err != nil {
				return err
			}
		}
		//先查权限
		var perms []sysModel.SysPermission
		//获取权限ID
		var permIds []int
		json.Unmarshal(data.PermIds, &permIds)
		tx.Model(&sysModel.SysPermission{}).Find(&perms, permIds)
		//替换权限角色关联关系
		err = tx.Model(data).Association("Permission").Replace(perms)
		if err != nil {
			return err
		}
		//更新casbin策略-先删除该角色所有权限
		_, err := CasbinServiceApp.Casbin().RemoveFilteredPolicy(0, data.Name)
		if err != nil {
			return err
		}
		//更新casbin策略-添加该角色拥有权限
		for _, perm := range perms {
			if _, err := CasbinServiceApp.Casbin().AddPolicy(data.Name, "admin", perm.Name, "allow"); err != nil {
				return err
			}
		}
		return nil
	})
}

//删除角色
func (r *RoleService) DelRole(ids *comRequest.IdsReq) error {
	return global.GvaDb.Transaction(func(tx *gorm.DB) error {
		//删除角色数据
		if err := global.GvaDb.Delete(&sysModel.SysRole{}, ids.Ids).Error; err != nil {
			return err
		}
		//删除相关权限数据（硬删）
		if err := tx.Unscoped().Where("sys_perm_id IN ?", ids.Ids).Delete(&sysModel.SysPermissionRole{}).Error; err != nil {
			return err
		}
		// 返回 nil 提交事务
		return nil
	})
}

// BuildTree 构建树结构数据,(由于需要保留菜单结构数据，因此每一次树结构菜单都需要在对应的service中实现，使用公共的树方法无法还原原始菜单数据)
func (r *RoleService) BuildTree(resources []*sysModel.SysRole) []*sysModel.SysRole {
	//定义根树，既id=0的根节点，我用的时候并不存在于数据库
	var rootResource = sysModel.SysRole{}
	//创建一个map，把父级相同的地址归纳起来
	DataMap := make(map[uint][]*sysModel.SysRole, len(resources))
	//寻找对应的父级，添加子节点集合
	for key := range resources {
		pid := resources[key].ParentId
		DataMap[pid] = append(DataMap[pid], resources[key])
	}
	for key := range resources {
		if resources[key].ParentId == 0 {
			rootResource.Children = append(rootResource.Children, resources[key])
		}
		resources[key].Children = DataMap[resources[key].ID]
	}
	// 添加完成，既建立树形关系完成
	return rootResource.Children
}
